<template>
  <a-row :gutter="[8,8]">
    <a-col :span="5">
      <div id="stencil" @dragstart="dragsssssss"/>
    </a-col>
    <a-col :span="14">
      <el-divider content-position="center">工艺流程图</el-divider>
      <div id="container"/>
    </a-col>
    <a-col :span="5">
      <a-form :model="formData">
        <a-form-item label="设备名" v-show="formData.id !== null">
          <a-select v-model:value="formData.id" placeholder="请选择数据" @change="onIdChange">
            <a-select-option
                v-for = "item in dropdownData.tableData"
                :key="item.id"
                :value = "item.id">
              {{ item.title }}
            </a-select-option>
          </a-select>
        </a-form-item>

        <a-form-item label="设备id" v-show="formData.content !== null">
          <a-input v-model:value="formData.content" readOnly />
        </a-form-item>
        <a-form-item label="流程图名称">
          <a-input v-model:value="formData.graphName"/>
        </a-form-item>

        <a-button @click="toJson">保存</a-button>
        <a-button @click="loadGraph">读取</a-button>
        <a-button @click="loadPlcDataInterval">读取运行数据</a-button>
        <a-button @click="stopPlcDataInterval">停止读取运行数据</a-button>
        <a-button @click="yellowLine">黄色点线</a-button>
        <a-button @click="skyLine">蓝色点线</a-button>
        <a-button @click="bkgraphOperation">背景清空/选择切换</a-button>
      </a-form>
    </a-col>
  </a-row>
</template>

<script lang="ts">
import {defineComponent, onMounted, onUnmounted, reactive, UnwrapRef} from "vue";
import {Graph, Shape, Node, Addon, Cell, Edge, EdgeView, Vector} from '@antv/x6';
import { addPd, findPdById, list, plcdatalist } from '@/api/equip'
import { RecycleOpt } from '@/utils/recycleOpt'
import { list as typeList } from '@/api/equiptype'


let tableData = [
  {
    id: 1,
    title: "循环泵1#",
    content: "hrz1-xhb-1",
  },
  // {
  //   id: 2,
  //   title: "补水箱2#",
  //   content: "hrz1-bsx-1",
  // },
  // {
  //   id: 3,
  //   title: "水表3#",
  //   content: "hrz1-sb-1",
  // },
]

interface FormDataModel {
  id: any;
  title: any;
  content: any;
  graphName: string;
}

interface EquipModel {
  id: number | null;
  equipNum: string;
  remark: string;
  typeId: number;
}

interface GraphModel {
  _id: string;
  cells: Array<any>;
}

interface EquipTypeModel {
  id: number | null;
  deviceType: string;
  otherDeviceAttrId: number | null;
  remark: string;
}

interface PlcdataModel {
  deviceCode: string;
  indicatorId: string;
  indicatorName: string;
  plcVariableValue: string;
}

export default defineComponent({
  setup() {
    let graph: Graph;
    let stencil: Addon.Stencil;
    let curCel: Cell | null;
    let graphId: string;
    let plcInterval: number;
    let dnd: Addon.Dnd;
    const equipNums: Array<string> = []
    //const bkgraphpath = 'hrz.png'
    const bkgraph = reactive({bkgraphpath:'hrz.png'})
    console.log('bkgraph',bkgraph.bkgraphpath)
    // 中间画布
    const buildGraph = (): void =>{
      graph = new Graph({
        container: document.getElementById('container') as HTMLElement,
        height: 600,
        background: {
          image: require(`./../../assets/${bkgraph.bkgraphpath}`) ,
          position: {
            x:0,
            y:0
          },
          size: {
            width: 1600,
            height: 600,
          }
        },
        resizing: {
          enabled: true,
        },
      });

      // const graphContent = localStorage.getItem("workmanshipGraph");
      // if(typeof graphContent === 'undefined' || graphContent == null || graphContent === '') {
      //   console.log("graphContent is null");
      // } else {
      //   graph.fromJSON(JSON.parse(graphContent));
      // }
    }

    // 左侧模板
    const buildStencil = (): void => {
      stencil = new Addon.Stencil({
        target: graph,
        stencilGraphWidth: 280,
        // search: { rect: true },
        collapsable: true,
        groups: [
          {
            name: 'basic',
            title: '设备类型',
            // 高度
            graphHeight: 180,
          },
          {
            name: 'pipe',
            title: '管',
            // 高度
            graphHeight: 180,
          },
          {
            name: 'combination',
            title: '组合节点',
            // 布局选项
            layoutOptions: {
              // 每行几列
              columns: 1,
              // 左侧边距
              marginX: 60,
            },
            graphHeight: 260,
          },
          // {
          //   name: 'group',
          //   title: '节点组',
          //   graphHeight: 100,
          //   layoutOptions: {
          //     columns: 1,
          //     marginX: 60,
          //   },
          // },
        ]
      });

      // dnd = new Addon.Dnd({
      //   target: graph,
      //   getDropNode: (node) => {
      //     console.log('dragnode=================',node)
      //     return node.clone({ keepId: true })
      //   },
      // });

      document.querySelector('#stencil')?.appendChild(stencil.container)
    }

    const dragsssssss = (e: any) => {
      console.log('drag',e)
    }
    // 左侧模板加载数据 stencil.load
    const stencilLoadData = () => {
      // createNode方式
      const bizNode1 = graph.createNode({
        shape: "image",
        width: 100,
        height: 50,
        attrs: {
          label: {
            fontSize: 12,
            text: "循环泵"
          },
        },
      imageUrl: require('@/assets/xhb.jpg'),
      data: {
        type: '2'
      }
      })
      // 构造函数方式
      const bizNode2 = new Shape.Image({
        width: 100,
        height: 50,
        attrs: {
          label: {
            fontSize: 12,
            text: "补水箱"
          },
        },
      imageUrl: require('@/assets/bsx.png'),
      data: {
        type: '1'
      }
      
      });
      // 节点元数据方式
      const bizNode3: Node.Metadata = {
        shape: "image",
        width: 100,
        height: 50,
        attrs: {
          label: {
            fontSize: 12,
            text: "水表"
          },
        },
      imageUrl: require('@/assets/sb.jpg'),
      data: {
        type: '3'
      }
      }
      const bizNode4 = graph.createNode({
        shape: "rect",
        width: 100,
        height: 10,
        attrs: {
          // 指定 rect 元素的样式
          body: { 
            stroke: 'lightblue', // 边框颜色
            fill: 'lightblue',   // 填充颜色
          },
          label: {
            fontSize: 12,
            text: ""
          },
        },
      data: {
        type: '5'
      }
      })
      const bizNode5 = graph.createNode({
        shape: "rect",
        width: 100,
        height: 5,
        attrs: {
          // 指定 rect 元素的样式
          body: { 
            stroke: 'none', // 边框颜色
            fill: 'blue',   // 填充颜色
          },
          label: {
            fontSize: 12,
            text: ""
          },
        },
      data: {
        type: '6'
      }
      })
      
      const bizNode7 = graph.createNode({
        shape: "rect",
        width: 5,
        height: 50,
        attrs: {
          // 指定 rect 元素的样式
          body: { 
            stroke: 'none', // 边框颜色
            fill: 'blue',   // 填充颜色
          },
          label: {
            fontSize: 12,
            text: ""
          },
        },
      data: {
        type: '7'
      }
      })

      bizNode7.attr('body/fill', {
        type: 'linearGradient',
        stops: [
          { offset: '0%',  color: '#E67E22' },
          { offset: '20%', color: '#D35400' },
          { offset: '40%', color: '#E74C3C' },
          { offset: '60%', color: '#C0392B' },
          { offset: '80%', color: '#F39C12' },
        ],
      })
      bizNode5.attr('body/fill', {
        type: 'linearGradient',
        stops: [
          { offset: '0%',  color: '#E67E22' },
          { offset: '20%', color: '#D35400' },
          { offset: '40%', color: '#E74C3C' },
          { offset: '60%', color: '#C0392B' },
          { offset: '80%', color: '#F39C12' },
        ],
      })
      
      const nodes: (Node | Node.Metadata)[] = []

      typeList(null).then(res => {
        const { rows } = res.data
        console.log('typelist', rows)

        rows.forEach((val: EquipTypeModel, index: number)=>{
          const bizNode6 = new Shape.Image({
            position: {
              x:50,
              y:50
            },
            width: 100,
            height: 50,
            ports: [],
            attrs: {
              label: {
                fontSize: 12,
                text: val.deviceType
              },
            },
          imageUrl: require('@/assets/'+val.remark),
          data: {
            type: val.otherDeviceAttrId
          },
          zIndex: 1
          
          });
          nodes.push(bizNode6);
          
        })
        
        stencil.load([...nodes], 'basic')
      })
      console.log('nodes',nodes)
      //stencil.load([bizNode1, bizNode2, bizNode3], 'basic')
      stencil.load([bizNode4,bizNode5,bizNode7], 'pipe')
      //stencil.load([edge1], 'pipe')
      
    }

    // 表单数据定义
    const formData: UnwrapRef<FormDataModel> = reactive({
      id: null,
      title: null,
      content: null,
      graphName: '',
    });
    // 所有下拉数据
    const dropdownData: UnwrapRef<any> = reactive({
      tableData: [{
        id: null,
        title: null,
        content: null,
      }],
    });

    // 初始化事件
    const initEvent = () => {
      // graph.on('node:mousedown',({e,cell}) => {
      //   console.log('node:mousedown',cell);
      //   dnd.start(cell, e)
      // });
      graph.on('node:added', ({ node }) => {
        const { x, y } = node.position()
        console.log('node:added', x, y, node.id)
        //node.id = 
      })
      graph.on('node:mouseenter', ({ node }) => {
          node.addTools({
            name: 'button-remove',
            args: {
              x: 0,
              y: 0,
              offset: { x: 10, y: 10 },
            },
          })
      })
      graph.on('edge:contextmenu', ({ cell }) => {
                //if (cell === edge2) {
                    cell.addTools('vertices', 'onhover')
                    cell.addTools(['source-arrowhead','target-arrowhead','button-remove'])
                //}
            })

            

      graph.on('edge:mouseleave', ({ cell }) => {
          //if (cell.hasTools('onhover')) {
              cell.removeTools()
          //}
      })
      graph.on('node:mouseleave', ({ node }) => {
        node.removeTools()
      })
      graph.on('cell:contextmenu', ({cell}) => {
        console.log(cell.getAttrs())
        console.log(cell.getData())
        // 将之前被选中的节点样式清除
        curCel?.attr('body/stroke', null)
        // 新的节点赋值
        curCel = cell
        // 新的节点边框样式设置为红色
        //curCel?.attr('body/stroke', "red")

        // 将cell data中Id进行赋值
        const type = cell.getData()?.type;
        console.log("==type=="+type);
        formData.id = cell.getData()?.id
        const queryData: EquipModel = {
          id: null,
          remark: '',
          equipNum: '',
          typeId: type
        }
        
        if(formData.id){
          // 模拟请求数据
          setTimeout(() => {
            list(queryData).then(res => {
              console.log('equip list',res)
              const { data } = res
              const { rows } = data
              
              tableData = rows.map((val: EquipModel, index: number, array: Array<EquipModel>)=>{
                  console.log('dd1',index,val, array,)
                  
                  return { id: val.id, title: val.remark, content: val.equipNum};
              });
              console.log('cell:click',tableData)
              dropdownData.tableData = tableData
              const tableDataRow = tableData.filter(item => item.id === formData.id)[0];
              formData.title = tableDataRow.title
              formData.content = tableDataRow.content
            })
          }, 100)
        } else {
          list(queryData).then(res => {
              console.log('equip list',res)
              const { data } = res
              const { rows } = data
              
              tableData = rows.map((val: EquipModel, index: number, array: Array<EquipModel>)=>{
                  console.log('dd1',index,val, array,)
                  
                  return { id: val.id, title: val.remark, content: val.equipNum};
              });
              console.log('cell:click',tableData)
              dropdownData.tableData = tableData
              formData.title = null
              formData.content = null
            })
        }
      });
    }
    onMounted(() => {
      buildGraph();
      buildStencil();
      stencilLoadData();
      initEvent();
      // 模拟请求数据
      setTimeout(()=>{
        console.log('fetch dropdown')
        list(formData).then(res => {
          console.log('equip list',res)
          const { data } = res
          const { rows } = data
          
          tableData = rows.map((val: EquipModel, index: number, array: Array<EquipModel>)=>{
              console.log('dd1',index,val, array,)
              
              return { id: val.id, title: val.remark, content: val.equipNum};
          });
          console.log(tableData)
          dropdownData.tableData = tableData
        })
        //dropdownData.tableData= tableData;
      },1000)

      //const opt : RecycleOpt = new RecycleOpt()
      //opt.operateCycle(() => { console.log('recycleopt')});

    })

    onUnmounted(() => {
      clearInterval(plcInterval)
    })

    const onIdChange = () =>{
      console.log('onIdChange',tableData)
      // 模拟请求
      setTimeout(()=>{
        const tableDataRow = tableData.filter(item => item.id === formData.id)[0];
        formData.title = tableDataRow?.title;
        formData.content = tableDataRow?.content;

        curCel?.setData({
          id: formData.id,
          deviceCode: formData.content
        })
        curCel?.attr('label/text', formData.title)

      },100)
    }

    const toJson = () => {
      console.log(graph.toJSON())
      console.log('toJson background', graph.background.options.background)
      console.log('toJson background', graph.background)
      //localStorage.setItem("workmanshipGraph",JSON.stringify(graph.toJSON()));
      //bkgraph.bkgraphpath = 'image.png'
      //graph.drawBackground({ image: require(`./../../assets/${bkgraph.bkgraphpath}`) })
      //console.log(`${bkgraph.bkgraphpath}`)
      let backgroundurl = ''
      if(graph.background.options.background === undefined) {
        console.log('undefined')
        backgroundurl = ''
      } else {
        console.log('not undefined')
        backgroundurl = bkgraph.bkgraphpath
      }
      const data = { 
        _id: graphId, 
        background: backgroundurl, 
        belongType: "2",
        graphName: formData.graphName,
        tenantId: "1",
        orgId: "1",
        sourceId: '23437098536763392',
        stationId: '23437500800401408',
        //subareaId: "",
        ... graph.toJSON()
      }
      console.log('save',data)
      addPd(data).then(response => {
        console.log('addod',response)
        const res: any = response.data
        console.log(res)
      })
    }

    const loadGraph = () => {
      findPdById('29150406016278528').then(response => {
        console.log('loadgraph',response)
        const res: GraphModel = response.data.data
        console.log('loadgraph res',res._id, res.cells)
        graphId = res._id;
        graph.fromJSON(res.cells)
        graph.updateBackground()
        
      })
    }

    const loadPlcData = () => {
      console.log('loadPlcData==',graph.getNodes())
      
      const nodeMap: Map<string,Node<Node.Properties>> = new Map();
      graph.getNodes().map((val: Node, index: number, array: Array<Node>) => {
        console.log('loadPlcData== nodedata', val.data);
        if(val.data.deviceCode !== undefined && val.data.deviceCode !== '') {
          console.log('loadPlcData== nodedata not null', val.data);
          equipNums.push(val.data.deviceCode)
          nodeMap.set(val.data.deviceCode, val)
        }
      });
      console.log('loadPlcData== equipNums',equipNums)
      plcdatalist(equipNums).then(res => {
        console.log('plcdatalist',res)
        const  data: Array<PlcdataModel> = res.data.data
        console.log('loadPlcData== data',data)
        for(const item of data) {
          console.log('loadPlcData== item',item)
          const deviNode: Node<Node.Properties>|undefined = nodeMap.get(item.deviceCode);
          deviNode?.setAttrByPath("label/text", item.indicatorName+item.plcVariableValue)
        }
        
      })
    }
    const edge1  = {
        source: { x: 50, y: 40 },
        target: { x: 380, y: 40 },
        vertices: [
            { x: 40, y: 85 },
            { x: 200, y: 80 },
            { x: 200, y: 40 },
        ],
        attrs: {
            line: {
                stroke: 'GoldenRod',
                strokeWidth: 6,
                targetMarker: '',
                strokeDasharray: "5,5"

                // sourceMarker: {
                //     tagName: 'ellipse',
                //     rx: 20,
                //     ry: 10,
                //     cx: 20,
                //     fill: 'rgba(255,0,0,0.3)',
                // }
            },
        }
    }

    const edge2  = {
        source: { x: 50, y: 40 },
        target: { x: 380, y: 40 },
        vertices: [
            { x: 40, y: 85 },
            { x: 200, y: 80 },
            { x: 200, y: 40 },
        ],
        attrs: {
            line: {
                stroke: 'skyBlue',
                strokeWidth: 6,
                targetMarker: '',

                // sourceMarker: {
                //     tagName: 'ellipse',
                //     rx: 20,
                //     ry: 10,
                //     cx: 20,
                //     fill: 'rgba(255,0,0,0.3)',
                // }
            },
        }
    }

    const yellowLine = () => {
      console.log('yellowline')
      const edge = graph.addEdge(edge1);
      const view = graph.findViewByCell(edge) as EdgeView
      const token = Vector.create('circle', { r: 5, fill: 'GoldenRod' })
      const sendSignal: Function 
        = () => {view.sendToken(token.node, 2000, ()=> {
                    console.log('sendToken')
                    //sendSignal()
                  })
                }
      sendSignal()
      // 5s 后停止该动画
      //setTimeout(stop, 5000)
    }

    const skyLine = () => {
      console.log('skyLine')
      graph.addEdge(edge2);
    }

    const loadPlcDataInterval = () => {
      plcInterval = setInterval(() => {
                      loadPlcData()
                    }, 1000)
    }

    const stopPlcDataInterval = ()=> {
      clearInterval(plcInterval)
    }

    const bkgraphOperation = () => {
      graph.clearBackground()
    }

    return {
      formData,
      dropdownData,
      onIdChange,
      toJson,
      loadGraph,
      dragsssssss,
      loadPlcData,
      loadPlcDataInterval,
      stopPlcDataInterval,
      yellowLine,
      skyLine,
      bkgraphOperation
    }
  }
})
</script>

<style scoped lang="less">

</style>
